package eu.hellek.gba.server.rpc; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import com.beoui.geocell.model.BoundingBox; import com.google.appengine.api.datastore.GeoPt; import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; import com.googlecode.objectify.Key; import com.googlecode.objectify.Objectify; import eu.hellek.gba.model.Line; import eu.hellek.gba.model.PlanQuadrat; import eu.hellek.gba.model.Point; import eu.hellek.gba.model.UserFavouritePosition; import eu.hellek.gba.server.dao.Dao; import eu.hellek.gba.server.holders.ConnectingLineHolder; import eu.hellek.gba.server.utils.MyCostFunction; import eu.hellek.gba.server.utils.MyGeocellUtils; import eu.hellek.gba.server.utils.Utils; import eu.hellek.gba.shared.ConnectionProxy; import eu.hellek.gba.shared.ConnectionProxyComparator; import eu.hellek.gba.shared.LineProxy; import eu.hellek.gba.shared.LoginInfo; import eu.hellek.gba.shared.SearchResultProxy; import eu.hellek.gba.shared.UserFavouritePositionProxy; public class ExtractedFunctions { public SearchResultProxy getDirectConnections(float lat1, float lon1, float lat2, float lon2, boolean ignoreTrains, boolean ignoreSubte, String ipaddr) { final String functionName = "ExctractedFunctions:getDirectConnections()"; Objectify ofy = Dao.getInstance().getObjectify(); HashSet<Key<Line>> tabuTrainsSet = new HashSet<Key<Line>>(); ConnectionProxy connTren = null; if(ignoreTrains) { tabuTrainsSet.addAll(Dao.getTrainKeys()); } if(ignoreSubte) { tabuTrainsSet.addAll(Dao.getSubteKeys()); } else { // only run this search if the user allows subtes connTren = Dao.getInstance().indirectSearch(new GeoPt(lat1, lon1), new GeoPt(lat2, lon2), tabuTrainsSet, new HashSet<Key<Line>>(), ofy); double distanceBetweenPoints = Utils.distanceInMeters(new Point("", lat1, lon1, null), new Point("", lat2, lon2, null)); if(connTren != null && connTren.getDistance() > 3 * distanceBetweenPoints) { Logger.getLogger("ListPointsServiceImpl").log(Level.INFO, functionName + ": dropped a bad result with length " + connTren.getDistance() + " which would have used " + connTren.getLines().size() + " lines."); connTren = null; // very bad result, let's delete it } } float distNS = Utils.searchDistanceNS; float distWE = Utils.searchDistanceWE; // about 750m in each direction, creating a 1500x1500 square Collection<PlanQuadrat> pqs1 = Dao.getInstance().getPQsInBB(lat1+distNS, lon1+distWE, lat1-distNS, lon1-distWE, ofy); Collection<PlanQuadrat> pqs2 = Dao.getInstance().getPQsInBB(lat2+distNS, lon2+distWE, lat2-distNS, lon2-distWE, ofy); BoundingBox bbCells1Inner = new BoundingBox(lat1+(distNS/2), lon1+(distWE/2), lat1-(distNS/2), lon1-(distWE/2)); // 750/2 in each direction creating a 750x750 square BoundingBox bbCells2Inner = new BoundingBox(lat2+(distNS/2), lon2+(distWE/2), lat2-(distNS/2), lon2-(distWE/2)); HashSet<String> cellsInner = new HashSet<String>(MyGeocellUtils.bestBboxSearchCells(bbCells1Inner, new MyCostFunction())); cellsInner.addAll(MyGeocellUtils.bestBboxSearchCells(bbCells2Inner, new MyCostFunction())); Map<Key<Line>,Integer> set1 = new HashMap<Key<Line>,Integer>(); Map<Key<Line>,Integer> set2 = new HashMap<Key<Line>,Integer>(); Map<String,PlanQuadrat> pqs_map = new HashMap<String,PlanQuadrat>(); List<ConnectingLineHolder> connectingLines = new ArrayList<ConnectingLineHolder>(); HashSet<Key<Line>> mlkSet1 = new HashSet<Key<Line>>(); HashSet<Key<Line>> mlkSet2 = new HashSet<Key<Line>>(); HashSet<Key<Line>> mlkSet1Inner = new HashSet<Key<Line>>(); HashSet<Key<Line>> mlkSet2Inner = new HashSet<Key<Line>>(); HashSet<Key<Line>> tabuBusesSet = new HashSet<Key<Line>>(); for(PlanQuadrat pq : pqs1) { for(int i = 0; i < pq.getMainLineKeys().size(); i++) { Key<Line> k = pq.getMainLineKeys().get(i); if(!pq.getIgnore().get(i)) { if(!set1.containsKey(k) || pq.getIndicesMLK().get(i) > set1.get(k)) { set1.put(k, pq.getIndicesMLK().get(i)); mlkSet1.add(k); } if(cellsInner.contains(pq.getGeoCell())) { mlkSet1Inner.add(k); // System.err.println("innerset1 - added " + k); } } } pqs_map.put(pq.getGeoCell(), pq); // System.err.print("\"" + pq.getGeoCell() + "\", "); } for(PlanQuadrat pq : pqs2) { for(int i = 0; i < pq.getMainLineKeys().size(); i++) { Key<Line> k = pq.getMainLineKeys().get(i); if(!pq.getIgnore().get(i)) { if(!set2.containsKey(k) || pq.getIndicesMLK().get(i) > set2.get(k)) { set2.put(k, pq.getIndicesMLK().get(i)); mlkSet2.add(k); } if(cellsInner.contains(pq.getGeoCell())) { mlkSet2Inner.add(k); // System.err.println("innerset2 - added " + k); } } } pqs_map.put(pq.getGeoCell(), pq); // System.err.print("\"" + pq.getGeoCell() + "\", "); } // System.err.println(); /*HashSet<Key<Line>> mlkSetInner = new HashSet<Key<Line>>(mlkSet1Inner); mlkSetInner.addAll(mlkSet2Inner);*/ for(Key<Line> k : set1.keySet()) { if(set2.containsKey(k) ) { if(mlkSet1Inner.contains(k) && mlkSet2Inner.contains(k)) { tabuBusesSet.add(k); // System.err.println("Added to tabu-set because it is close: " + k); } if(set1.get(k) <= set2.get(k)) { connectingLines.add(new ConnectingLineHolder(k, set1.get(k), set2.get(k))); // Logger.getLogger("ListPointsServiceImpl").log(Level.INFO, functionName + ": Matching line: " + KeyFactory.keyToString(k1)); } else { tabuBusesSet.add(k); // System.err.println("Added to tabu-set because it is in reverse: " + k); } } } Collections.sort(connectingLines); if(connectingLines.size() > 10) { connectingLines.subList(10, connectingLines.size()).clear(); } Iterator<ConnectingLineHolder> il = connectingLines.iterator(); List<ConnectionProxy> conns = new LinkedList<ConnectionProxy>(); while(il.hasNext()) { ConnectingLineHolder temp = il.next(); // System.err.println(Dao.getInstance().getLineByKey(temp, em)); Point p1 = new Point("", lat1, lon1, null); Point p2 = new Point("", lat2, lon2, null); /* List<Point> points1 = Dao.getInstance().getPointsInBB(lat1+distNS, lon1+distWE, lat1-distNS, lon1-distWE, temp); List<Point> points2 = Dao.getInstance().getPointsInBB(lat2+distNS, lon2+distWE, lat2-distNS, lon2-distWE, temp); Point p1_min = closestPoint(p1, points1); Point p2_min = closestPoint(p2, points2);*/ Collection<Point> points1 = Dao.getInstance().getSearchPointsForLine(temp.getLineKey(), temp.getIndex1(), 50, ofy); Collection<Point> points2 = Dao.getInstance().getSearchPointsForLine(temp.getLineKey(), temp.getIndex2(), 50, ofy); Point p1_min = closestPoint(p1, points1); Point p2_min = closestPoint(p2, points2); List<LineProxy> lps = new LinkedList<LineProxy>(); lps.add(Utils.walk(p1, p1_min)); LineProxy lp = Utils.getConnection(p1_min, p2_min, ofy); List<Key<Line>> alternativesK = new LinkedList<Key<Line>>(); PlanQuadrat pq1 = pqs_map.get(Utils.computeGeoCell(p1_min)); if(pq1 == null) { pq1 = Dao.getInstance().getPlanQuadrat(Utils.computeGeoCell(p1_min), ofy); pqs_map.put(pq1.getGeoCell(), pq1); } PlanQuadrat pq2 = pqs_map.get(Utils.computeGeoCell(p2_min)); if(pq2 == null) { pq2 = Dao.getInstance().getPlanQuadrat(Utils.computeGeoCell(p2_min), ofy); pqs_map.put(pq2.getGeoCell(), pq2); } int counter = 0; for(Key<Line> k1 : pq1.getDirectLineKeys()) { if(!k1.equals(temp) // nicht der bus der eh schon genommen wird && !pq1.getMainLineKeys().contains(k1) // keine Main Lines, weil die sowieso als eigene Route gefunden und angezeigt werden && pq2.getDirectLineKeys().contains(k1) // in anfangs und end PQ gleicherma�en enthalten && pq1.getIndices().get(pq1.getDirectLineKeys().indexOf(k1)) // aufsteigender Index <= pq2.getIndices().get(pq2.getDirectLineKeys().indexOf(k1)) && counter < 10) { alternativesK.add(k1); counter++; // Logger.getLogger("ListPointsServiceImpl").log(Level.INFO, functionName + ": Matching line: " + KeyFactory.keyToString(k1)); } } for(Key<Line> k : alternativesK) { Line l = Dao.getInstance().getLineByKey(k, ofy); lp.addAlternativeLine(l.getLinenum() + " " + l.getRamal()); } lps.add(lp); lps.add(Utils.walk(p2_min, p2)); ConnectionProxy cp = new ConnectionProxy(lps); conns.add(cp); } for(Key<Line> k : tabuBusesSet) { mlkSet1.remove(k); mlkSet2.remove(k); mlkSet1Inner.remove(k); mlkSet2Inner.remove(k); } /*for(Key k : tabuBusesSet) { System.out.println("Tabu set contains: " + k); }*/ if(connTren != null) { conns.add(connTren); } Collections.sort(conns, new ConnectionProxyComparator()); List<String> mlkSet1String = new LinkedList<String>(); List<String> mlkSet2String = new LinkedList<String>(); if(mlkSet1Inner.size() >= 79) { for(Key<Line> k : mlkSet1Inner) { mlkSet1String.add("" + k.getId()); } } else { for(Key<Line> k : mlkSet1) { mlkSet1String.add("" + k.getId()); } } if(mlkSet2Inner.size() >= 79) { for(Key<Line> k : mlkSet2Inner) { mlkSet2String.add("" + k.getId()); } } else { for(Key<Line> k : mlkSet2) { mlkSet2String.add("" + k.getId()); } } if(conns.size() > 0) { return new SearchResultProxy(conns, mlkSet1String, mlkSet2String); } else { return new SearchResultProxy(SearchResultProxy.noResults, mlkSet1String, mlkSet2String); } } public SearchResultProxy getIndirectConnections(float lat1, float lon1, float lat2, float lon2, boolean ignoreTrains, boolean ignoreSubte, List<String> mlkSet1String, List<String> mlkSet2String) { if(mlkSet2String == null || mlkSet2String.size() == 0) { Logger.getLogger("ListPointsServiceImpl").log(Level.INFO, "getIndirectConnections(): mlkSet2 was empty, no search was done"); return new SearchResultProxy(SearchResultProxy.noResults, null, null); } else { Objectify ofy = Dao.getInstance().getObjectify(); HashSet<Key<Line>> tabuTrainsSet = new HashSet<Key<Line>>(); if(ignoreTrains) { tabuTrainsSet.addAll(Dao.getTrainKeys()); } if(ignoreSubte) { tabuTrainsSet.addAll(Dao.getSubteKeys()); } List<ConnectionProxy> connsIndirect = new LinkedList<ConnectionProxy>(); HashSet<Key<Line>> mlkSet = new HashSet<Key<Line>>();; for(String s : mlkSet1String) { mlkSet.add(new Key<Line>(Line.class, Long.parseLong(s))); } for(String s : mlkSet2String) { mlkSet.add(new Key<Line>(Line.class, Long.parseLong(s))); } ConnectionProxy result = Dao.getInstance().indirectSearch(new GeoPt(lat1, lon1), new GeoPt(lat2, lon2), tabuTrainsSet, mlkSet, ofy); if(result != null) { connsIndirect.add(result); } if(connsIndirect.size() > 0) { return new SearchResultProxy(connsIndirect, null, null); } else { return new SearchResultProxy(SearchResultProxy.noResults, null, null); } } } /* * can be used when all points are only belonging to the same line anyway */ private static Point closestPoint(Point thePoint, Collection<Point> points) { Point p = thePoint; // may be passed as transient point without line, key, etc. double dMin = 99999999.9; Point pMin = null; for(Point pCur : points) { double distCur = Utils.distanceApprox(pCur, p); if(distCur < dMin) { dMin = distCur; pMin = pCur; } } return pMin; } public LoginInfo login(String requestUri) { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); LoginInfo loginInfo = new LoginInfo(); if (user != null) { Objectify ofy = Dao.getInstance().getObjectify(); loginInfo.setLoggedIn(true); loginInfo.setEmailAddress(user.getEmail()); loginInfo.setNickname(user.getNickname()); loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri)); Collection<UserFavouritePosition> favs = Dao.getInstance().getUserFavouritePositions(user, ofy); if(favs != null && favs.size() > 0) { List<UserFavouritePositionProxy> favourites = new LinkedList<UserFavouritePositionProxy>(); for(UserFavouritePosition fav : favs) { favourites.add(new UserFavouritePositionProxy(fav.getName(), fav.getPos().getLatitude(), fav.getPos().getLongitude(), fav.getId().toString())); } loginInfo.setFavourites(favourites); } } else { loginInfo.setLoggedIn(false); loginInfo.setLoginUrl(userService.createLoginURL(requestUri)); } return loginInfo; } public UserFavouritePositionProxy addFavourite(UserFavouritePositionProxy fpp) { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { Objectify ofy = Dao.getInstance().getObjectify(); UserFavouritePosition toSave = new UserFavouritePosition(user, new GeoPt((float)fpp.getLat(), (float)fpp.getLon()), fpp.getName()); Dao.getInstance().addUserFavouritePosition(toSave, ofy); return new UserFavouritePositionProxy(fpp.getName(), fpp.getLat(), fpp.getLon(), toSave.getId().toString()); } else { return null; } } public String removeFavourite(String id) { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { Objectify ofy = Dao.getInstance().getObjectify(); Key<UserFavouritePosition> key = new Key<UserFavouritePosition>(UserFavouritePosition.class, Long.parseLong(id)); Dao.getInstance().deleteUserFavouritePosition(key, user, ofy); return "success"; } else { return "failed"; } } }